﻿// Decompiled with JetBrains decompiler
// Type: Netick.AdaptiveRemoteInterpolation
// Assembly: Netick, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null
// MVID: 6726ECA1-C773-4CF7-8952-E81B30D93B52
// Assembly location: D:\WorkSpaceDemo\UPM\NetickForUnity\Netick\Runtime\Netick.dll
// XML documentation location: D:\WorkSpaceDemo\UPM\NetickForUnity\Netick\Runtime\Netick.xml

using System.Numerics;

#nullable disable
namespace Netick;

public sealed class AdaptiveRemoteInterpolation : Interpolation
{
  internal RingBuffer<Tick> _buffer;
  internal RingBuffer<NetickAllocator> _snapshots;
  private Tick _from;
  private Tick _to;
  private float _bufferAsTime;
  private float _alpha;
  private float _currentLerpTime;
  private float _lastTime;
  private readonly FloatStats _packetTime;
  private int _ticks;
  private double _desiredBufferDelay = 2.0;
  private Entity _entity;
  private Vector3 _currentPos;
  private Vector3 _lastPos;

  /// <summary>Interpolation time in seconds.</summary>
  internal float CurrentBufferTime
  {
    get
    {
      return this._bufferAsTime + ((float) this.Engine._timer.Time - this._lastTime) - this._currentLerpTime;
    }
  }

  public override Tick From => this._from;

  public override Tick To => this._to;

  public override float Alpha => this._alpha;

  public override bool HasSnapshots => this.FromSnapshot != null && this.ToSnapshot != null;

  public float BufferTime => this.CurrentBufferTime;

  /// <summary>Time in seconds.</summary>
  public override float Time
  {
    get
    {
      return NetickUtils.Lerp((float) this._from.Value, (float) this._to.Value, this._alpha) * this.Engine.FixedDeltaTime;
    }
  }

  internal AdaptiveRemoteInterpolation(NetickEngine engine, Entity entity, int bufferSize)
    : base(engine)
  {
    this._entity = entity;
    this._packetTime = new FloatStats(bufferSize);
    this._buffer = new RingBuffer<Tick>(bufferSize * 2);
    this._snapshots = new RingBuffer<NetickAllocator>(bufferSize * 2);
  }

  public void Reset()
  {
    this._bufferAsTime = 0.0f;
    this._ticks = 0;
    this._alpha = 0.0f;
    this._currentLerpTime = 0.0f;
    this._buffer.FastClear();
    this._snapshots.FastClear();
    NetickLogger.Log((object) "AdaptiveRemoteInterpolation reset");
  }

  internal void Update(
    int serverDivisor,
    float rtt,
    ref ClientReplicatorData predicatedCrd,
    ref ClientReplicatorData authCrd,
    AdaptiveReplicator replicator)
  {
    float fixedDeltaTime = this.Engine.FixedDeltaTime;
    Vector3 vector3 = Vector3.op_Subtraction(this._currentPos, this._lastPos);
    Vector3 objPos = Vector3.op_Addition(this._currentPos, Vector3.op_Multiply((float) (40.0 * (double) rtt / 1.0), Vector3.op_Multiply(vector3, 3f)));
    int num1 = serverDivisor + (replicator.GetDivisorClient(objPos, ref predicatedCrd) - 1);
    int num2 = serverDivisor + (replicator.GetDivisorClient(this._currentPos, ref authCrd) - 1);
    this._desiredBufferDelay = (double) fixedDeltaTime * (double) num2 + (double) fixedDeltaTime * 0.4 + (double) this._packetTime.StdDeviation * 4.0;
    if (this._buffer.Count < 2)
    {
      this._ticks = 0;
      if (this._entity.RawId != 2)
        return;
      NetickLogger.Log((object) $"{$"Id {this._entity.RawId}  predicatedObjectDivisor {num1} -- lag, ticks: "}{this._ticks.ToString()} |  buffer count: {this._buffer.Count.ToString()}");
    }
    else
    {
      this._from = this._buffer[0];
      this._to = this._buffer[1];
      float num3 = (float) (this.To - this.From) * this.Engine.FixedDeltaTime;
      double num4 = (double) this.CurrentBufferTime - this._desiredBufferDelay;
      float num5 = 1f;
      double num6 = 0.035;
      double num7 = (double) this.CurrentBufferTime - ((double) fixedDeltaTime * (double) num1 + (double) fixedDeltaTime * 0.4 + (double) this._packetTime.StdDeviation * 4.0);
      if (this._ticks < 2 * num2)
      {
        if (this._entity.RawId != 2)
          return;
        NetickLogger.Log((object) $"{this._entity.RawId} -- _ticks < (2 * serverDivisor))");
      }
      else
      {
        if (num7 < -num6)
        {
          if (this._entity.RawId == 2)
            NetickLogger.Log((object) $"*** slowing down {num2 != num1}");
          num5 = num2 == num1 ? (num7 < -(double) fixedDeltaTime * 3.0 ? 0.9f : 0.99f) : 0.9f;
        }
        else if (num4 > num6)
          num5 = num4 > (double) fixedDeltaTime * 3.0 ? 1.2f : 1.01f;
        else if (num4 < -num6)
        {
          if (this._entity.RawId == 2)
            NetickLogger.Log((object) $"slowing down {num2 != num1}");
          num5 = num4 < -(double) fixedDeltaTime * 3.0 ? 0.89f : 0.99f;
        }
        if ((double) this._currentLerpTime < (double) num3)
        {
          this._currentLerpTime += this.Engine._timer._deltaTime * num5;
          this._alpha = this._currentLerpTime / num3;
        }
        if ((double) this._currentLerpTime > (double) num3)
        {
          for (; (double) this._alpha > 1.0; --this._alpha)
          {
            if (this._buffer.Count == 0)
            {
              this._currentLerpTime = 0.0f;
              break;
            }
            this.Dequeue();
            this._bufferAsTime -= num3;
            this._currentLerpTime -= num3;
          }
          if (this._buffer.Count < 2)
          {
            this._bufferAsTime = 0.0f;
            this._currentLerpTime = 0.0f;
            if (this._entity.RawId == 2)
              NetickLogger.Log((object) "LagFinish!");
          }
        }
        this._alpha = this._currentLerpTime / num3;
        if (this._buffer.Count >= 2)
        {
          this._from = this._buffer[0];
          this._to = this._buffer[1];
          this.FromSnapshot = this._snapshots[0];
          this.ToSnapshot = this._snapshots[1];
        }
        else
        {
          if (this._entity.RawId == 2)
            NetickLogger.Log((object) $"{this._entity.RawId}   End no states");
          this._ticks = 0;
        }
      }
    }
  }

  private void Dequeue()
  {
    this._buffer.RemoveFromStart(1);
    this._snapshots.RemoveFromStart(1);
  }

  private void Enqueue(Tick newTick, NetickAllocator snapshot)
  {
    this._buffer.Add(newTick);
    this._snapshots.Add(snapshot);
  }

  internal void AddSnapshot(Tick newTick, NetickAllocator newState, Vector3 newPos)
  {
    this._lastPos = this._currentPos;
    this._currentPos = newPos;
    double time = this.Engine._timer.Time;
    float num1 = (float) this.Engine._timer.Time - this._lastTime;
    this._lastTime = (float) time;
    this._packetTime.Update(num1);
    if (this._buffer.Count == 0)
    {
      this.Enqueue(newTick, newState);
      this._bufferAsTime += this.Engine.FixedDeltaTime;
    }
    else
    {
      int num2 = newTick - this._buffer.Last;
      this.Enqueue(newTick, newState);
      this._bufferAsTime += (float) num2 * this.Engine.FixedDeltaTime;
      this._ticks += num2;
      if (!this._buffer.IsFull)
        return;
      this.Reset();
    }
  }
}
